﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Mefisto4.Core.MEF;

namespace Mefisto4.Core.MVC
{
    public class ControllerExistenceContraint : IRouteConstraint
    {
        public CompositionContainer Container
        {
            get { return CompositionContainerFactory.CreateContainer(); }
        }

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (!values.ContainsKey(parameterName))
                return false;

            var controllerName = values[parameterName].ToString();

            var namespaces = GetNamespaceFromRoute(route);

            var export = Container.GetExports<IController, IDictionary<String, object>>()
                                  .FirstOrDefault(exp => exp.Metadata
                                                            .ContainsKey(Constants.ControllerNameMetadataName)
                                                      && exp.Metadata[Constants.ControllerNameMetadataName]
                                                            .ToString()
                                                            .ToLowerInvariant()
                                                            .Equals(controllerName.ToLowerInvariant())
                                                      && (namespaces == null
                                                        || !namespaces.Any()
                                                        || namespaces.Any(n => exp.Metadata[Constants.ControllerNamespaceMetadataName]
                                                                                  .ToString()
                                                                                  .ToLowerInvariant()
                                                                                  .StartsWith(n.ToLowerInvariant()))));


            return export != null;
        }

        #region Internal Methods

        private static IEnumerable<string> GetNamespaceFromRoute(Route route)
        {
            object routeNamespacesObj;

            if (route != null
                && route.DataTokens.TryGetValue("Namespaces", out routeNamespacesObj))
            {
                return routeNamespacesObj as IEnumerable<string>;
            }

            return null;
        }

        #endregion
    }
}